local util = require "util"
local conf = require "conf"
local require = require
local setmetatable = setmetatable
local error = error
local table = table
local ngx = ngx
local os = os
local string = string
local tonumber = tonumber
local pairs = pairs
local io = io
local type = type
package.cpath = "/usr/nginx/?.so;;"
local json = require 'cjson'
local gh = require 'iwi'
module(...)
_VERSION = '0.1'

function  create(user, args)
    local db = conf.get_mysql()
    local sql = "INSERT INTO `map_data` SET"
    local lng = args.lng or args.lon
    if args.lat then
        sql = sql .. " lat = " .. tonumber(args.lat) .. ","
    end
    if lng then
        sql = sql .. " lng = " .. tonumber(lng) .. ","
    end
    if args.x then
        sql = sql .. " x = " .. args.x .. ","
    end
    if args.y then
        sql = sql .. " y = " .. args.y .. ","
    end
    if args.alt then
        sql = sql .. " alt = " .. tonumber(args.alt) .. ","
    end
    if args.lat and lng then
        sql = sql .. " geohash = '" .. gh.encode(args.lat, lng, 8) .. "',"
    end

    if args.index_id then
        sql = sql .. " index_id = " .. args.index_id .. ","
    end

    sql = sql .. " create_time = " .. os.time() .. ","

    sql = sql:sub(1, -2)
    ngx.log(ngx.ERR, sql)
    local res = db:query(sql)
    return res
end


function createIndex(user, args)
    local db = conf.get_mysql()
    local sql = "INSERT INTO `map_index` SET"
    local lng = args.center_lng or args.center_lon
    if args.center_lat then
        sql = sql .. " center_lat = " .. tonumber(args.center_lat) .. ","
    end
    if lng then
        sql = sql .. " center_lng = " .. tonumber(lng) .. ","
    end
    if args.name then
        sql = sql .. " name = '" .. args.name .. "',"
    end

    if args.id then
        sql = sql .. " id = " .. args.id .. ","
    end

    if args.radius then
        sql = sql .. " radius = " .. args.radius .. ","
    end
    sql = sql .. " create_time = " .. os.time() .. ","

    sql = sql:sub(1, -2)
    ngx.log(ngx.ERR, sql)
    local res = db:query(sql)
    return res
end

function createController(user, args)
    local db = conf.get_mysql()

    local res = create(user, args)
    if not res or res.affected_rows < 1 then
        ngx.print(json.encode({
            err = 1,
            msg = '创建失败'
        }))
        ngx.exit(200)
    else
        local insert_id = res.insert_id
        if insert_id < 1 then
            res = db:query("SELECT LAST_INSERT_ID() AS insert_id")
            if res and res[1] and res[1].insert_id then
                insert_id = res[1].insert_id
            end
        end
        ngx.print(json.encode({
            err = 0,
            id = insert_id,
            msg = '创建成功'
        }))
        ngx.exit(200)
    end 
end

function delete(user, args)
    local id = args.id
    local db = conf.get_mysql()
    local res = db:query("DELETE FROM `map_data` WHERE id = " .. id )
    return res
end

function deleteController(user, args)
    if not args.id then
        ngx.print(json.encode({
            err = 2,
            msg = '缺少id'
        }))
    end
    local res = delete(user, args)
    if not res or res.affected_rows < 1 then
        ngx.print(json.encode({
            err = 1,
            msg = '更新失败'
        }))
        ngx.exit(200)
    else 
        ngx.print(json.encode({
            err = 0,
            msg = res
        }))
        ngx.exit(200)
    end
end

function search(user, args)
    local db = conf.get_mysql()
    local now  = os.time()

    local sql = "SELECT * FROM `map_data` WHERE 1=1";
    if args.geohash then
        sql = sql .. " AND `map_data`.geohash like '%" .. args.geohash .. "%'"
    end

    if args.geohashes then
        if type(args.geohashes) == 'string' then
            args.geohashes = json.decode(args.geohashes)
        end
        sql = sql .. " AND "
        for k,v in pairs(args.geohashes) do
            sql = sql .. " `map_data`.geohash like '%" .. v .. "%' OR"
        end
        sql = sql:sub(1, -4)
    end

    if args.id then
        sql = sql .. " AND `map_data`.id = " .. args.id
    end

    if args.x then
        sql = sql .. " AND `map_data`.x = " .. args.x
    end

    if args.y then
        sql = sql .. " AND `map_data`.y = " .. args.y
    end

    local res = db:query(sql)
    ngx.log(ngx.ERR, json.encode(res))
    return res
end

function searchIndex(user, args)
    local db = conf.get_mysql()
    local now  = os.time()

    local sql = "SELECT * FROM `map_index` WHERE 1=1";
    
    if args.radius then
        sql = sql .. " AND radius <= " .. args.radius
    end

    if args.id then
        sql = sql .. " AND `map_data`.id = " .. args.id
    end

    local res = db:query(sql)
    ngx.log(ngx.ERR, json.encode(res))
    return res
end

function searchController(user, args)
    local res = search(user, args)
    if not res then
        ngx.print(json.encode({
            err = 1,
            msg = '未能找到地图点'
        }))
        ngx.exit(200)
    else
        ngx.print(json.encode({
            err = 0,
            msg = res
        }))
        ngx.exit(200)
    end
end

function getTodoMapData(user, args)--代办
    local db = conf.get_mysql()
    local version = require 'version'
    local res = version.search(user, {["origin"] = "map", ["state"] = 0})
    return res
end

local function parseLine(line)
    local res = {}
    local arr = util.split(line, ",")
    for k,v in pairs(arr) do
        local kv = util.split(v, "=")
        res[util.trim(kv[1])] = tonumber(kv[2])
    end
    return res
end

function parseData(user, args)
    local res = getTodoMapData(user, args)
    local version = require 'version'
    -- ngx.log(ngx.ERR, json.encode(res))
    local start_p = nil
    local end_p = nil
    local path = "/opt/xyitech/static/"
    local jsonData = {}
    if res then
        for k,v in pairs(res) do
            local index_id = v.version_id
            local lastX = 0
            local thisLine = {}
            for line in io.lines(path .. v.file_name) do
                local lineTable = parseLine(line)

                if lineTable.x ~= lastX then
                    lastX = lineTable.x
                    if #thisLine ~= 0 then
                        table.insert(jsonData, thisLine)
                    end
                    thisLine = {lineTable.alt}
                else
                    table.insert(thisLine, lineTable.alt)
                end

                -- table.insert(jsonData, lineTable)
                lineTable.index_id = index_id
                if not start_p then
                    start_p = lineTable
                end
                ngx.log(ngx.ERR, json.encode(lineTable))
                end_p = lineTable
                create(user, lineTable)
            end
            if #thisLine ~= 0 then
                table.insert(jsonData, thisLine)
            end
            local indexArgs = {}
            indexArgs.id = index_id
            indexArgs.center_lat = (start_p.lat + end_p.lat) / 2
            indexArgs.center_lng = (start_p.lon + end_p.lon) / 2
            indexArgs.name = v.comment
            indexArgs.radius = util.distance(start_p, end_p) / 2
            createIndex(user, indexArgs)


            local file, err = io.open(path .. index_id..".json", "w+")
            file:write(json.encode(jsonData))
            file:close()
            local res = version.update(user, {["id"] = v.id, ["state"] = 1})
        end
    end

    ngx.print(json.encode({
        err = 0,
        msg = "处理完毕"
    }))
    ngx.exit(200)
end

function setGeoHashesFromRoute(route)
    local geohashes, mapInfo = {}, {}
    for k,v in pairs(route) do
        v.geohash = gh.encode(tonumber(v.lat), tonumber(v.lng), 8)
        table.insert(geohashes, v.geohash)
    end
    ngx.log(ngx.ERR, json.encode(route))
    local res = search({}, {["geohashes"] = geohashes})
    for k,v in pairs(res) do
        mapInfo[v.geohash] = {["alt"] = v.alt, ["x"] = v.x, ["y"] = v.y}
    end
    if res then
            ngx.log(ngx.ERR, json.encode(route))

        for k,v in pairs(route) do
                -- ngx.log(ngx.ERR, k)
                        -- ngx.log(ngx.ERR, v)
            -- ngx.log(ngx.ERR, json.encode(v))

            if type(v) == 'table' and mapInfo[v.geohash] then
                v.map_alt = mapInfo[v.geohash].alt
                v.x = mapInfo[v.geohash].x
                v.y = mapInfo[v.geohash].y
            else
                v.map_alt = 0
            end
        end
    end
    return route
end

function assignMapIndex(route)
    local mapIndexes = searchIndex({}, {})
    local passIndexes = {}
    for k,v in pairs(mapIndexes) do
        local pass = true
        local avg = 0
        for i,r in pairs(route) do
            local distance = util.distance({["lng"] = v.center_lng, ["lat"] = v.center_lat}, r)
            ngx.log(ngx.ERR, distance)
            if distance > v.radius then
                pass = false
            end
            avg = avg + distance
        end
        if pass then
            table.insert(passIndexes, {["id"] = v.id, ["avg"] = avg / #route})
        end
    end

    table.sort(passIndexes, function(a, b) return a.avg < b.avg end)
    local index = passIndexes[1] or {}
    return index.id or 0
end

function default(args)
    local user = conf.parse_token(args, "spoint")
    if args.action == 'create' then
        createController(user, args)
    elseif args.action == 'update' then
        updateController(user, args)
    elseif args.action == 'search' then
        searchController(user, args)
    elseif args.action == 'delete' then
        deleteController(user, args)
    elseif args.action == 'parseData' then
        parseData(user, args)
    end
end

local class_mt = {
    __newindex = function (table, key, val)
        error('attempt to write to undeclared variable "' .. key .. '"')
    end
}
setmetatable(_M, class_mt)
